#include "utils.h"

/*
* @brief: 交换unsigned short类型数据的高低位
*/
uint16_t swap_uint16(uint16_t value)
{
    return (value << 8) | (value >> 8);
}
/*
* @brief: 交换short类型数据的高低位
*/
int16_t swap_int16(int16_t value)
{
    return (value << 8) | ((value >> 8) & 0xFF);
}
/*
* @brief: 交换unsigned int类型数据的高低位
*/
uint32_t swap_uint32(uint32_t value)
{
    value = ((value << 8) & 0xFF00FF00) | ((value >> 8) & 0xFF00FF);
    return (value << 16) | (value >> 16);
}
/*
* @brief: 交换int类型数据的高低位
*/
int32_t swap_int32(int32_t value)
{
    value = ((value << 8) & 0xFF00FF00) | ((value >> 8) & 0xFF00FF);
    return (value << 16) | ((value >> 16) & 0xFFFF);
}
/*
* @brief: 交换无符号8字节数据类型数据的高低位
*/
uint64_t swap_uint64(uint64_t value)
{
    value = ((value << 8) & 0xFF00FF00FF00FF00ULL) | ((value >> 8) & 0x00FF00FF00FF00FFULL);
    value = ((value << 16) & 0xFFFF0000FFFF0000ULL) | ((value >> 16) & 0x0000FFFF0000FFFFULL);
    return (value << 32) | (value >> 32);
}

inline int round_up(int val, int rnd)
{
    return val >= 0 ? ((val + rnd - 1) / rnd) * rnd : (val / rnd) * rnd;
}

void convert_hex_to_ascii_string(char *hex_data, char *ascii_string)
{
    int i,j;
    for (i = 0, j = 0; i < strlen(hex_data); i += 2, j++)
    {
        char byte_str[3] = {hex_data[i], hex_data[i + 1], '\0'};
        ascii_string[j] = (char)strtol(byte_str, NULL, 16);
    }

    ascii_string[strlen(hex_data) / 2] = '\0';
}

void dump_hex(char *head_text, unsigned char *data, uint32_t len)
{
	int i;
    uint32_t ret = 0;
    char buf[512] = {0};

    ret += sprintf(buf + ret, "%s hex[len=%d]:", head_text, len);
	for(i = 0; i < len; i++){
		ret += sprintf(buf + ret, "%02X ", data[i]);
        if(ret > 512){
            char tmp_buf[512] = {0};
            ret = 512;
            printf("MAX dump 512 bytes\n");
            sprintf(tmp_buf, "%s hex[len=%d]:", head_text, ret);
            memcpy(buf, tmp_buf, strlen(tmp_buf) - 1);
            break;
        }
    }
    ret += sprintf(buf + ret, "\n");
    // log_d("%s", buf);
    printf("%s", buf);
}

uint8_t modbus_xor(unsigned char * data, uint16_t len)
{
    uint16_t i;
    uint32_t sum = 0;

    sum = data[0];
    for(i = 1; i < len; i++){
        sum ^= data[i];
    }
    return (uint8_t)(sum & 0xff);
}

uint8_t modbus_sum(unsigned char * data, uint16_t len)
{
    uint16_t i;
    uint32_t sum = 0;

    for(i = 0; i < len; i++){
        sum += data[i];
    }
    return (uint8_t)(sum & 0xff);
}

uint16_t modbus_crc16(unsigned char * data, uint16_t len)
{
    uint16_t i, j;
    uint16_t crcdata = 0xFFFF;

    for(i = 0; i < len; i++){
        crcdata ^= *data;
        
        for(j = 0; j < 8; j++){
            if(crcdata & 0x01){
                crcdata >>= 1;
                crcdata ^= 0xA001;
            }else{
                crcdata >>= 1;
            }
        }
        data++;
    }
    return crcdata;
}

void tea_decrypt (uint32_t* v, uint32_t* key) 
{
	uint32_t v0 = v[0], v1 = v[1], sum = 0xC6EF3720, i;
	uint32_t delta = 0x9e3779b9;
	uint32_t k0 = key[0], k1 = key[1], k2 = key[2], k3 = key[3];
	
	for (i = 0; i < 32; i++) {
		v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
		v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
		sum -= delta;
	}
	
	v[0] = v0;
	v[1] = v1;
}

int32_t search_string_from_list(char *str, char** list, uint32_t arry_len) 
{
    int32_t ret = 0;

    for(int i = 0; i < arry_len; i++){
        if(strcmp(str, list[i]) == 0){
            ret = 1;
            return ret;
        }
    }

    return ret;
}

void save_file(char *filename, void* data, uint32_t length)
{
	FILE* fp;

	fp = fopen(filename, "wb+");
	if(fp){
		fwrite(data, length, 1, fp);
		fclose(fp);
	}

	return;
}

int32_t create_path(char *path)
{
    int32_t ret = 0;

    if(!path){
        return -1;
    }
    if(access(path , F_OK) == 0){
        // log_w("exists dir:%s\n", path);
        return 0;
    }

    int i,len;
	char str[100];
	strcpy(str, path);
	len = strlen(str);
	for(i = 0; i < len; i++) {
		if(str[i] == '/') {
            str[i] = '\0';
			if(access(str, F_OK) != 0){
				mkdir(str, 0777);
            }
			str[i] ='/';
		}
	}
	if( len > 0 && access(str , F_OK) != 0){
		mkdir(str, 0777);
    }

    return ret;
}

uint16_t argb8888_to_argb1555(uint32_t color)
{
	uint32_t a = (((color&0xff000000)>>24) +127)/255;
	uint32_t r = (((color&0x00ff0000)>>16)*31 +127)/255;
	uint32_t g = (((color&0x0000ff00)>>8)*31 +127)/255;
	uint32_t b = (((color&0x000000ff))*31 +127)/255;

	uint16_t argb1555 = (a << 15) | (r <<  10) | (g << 5) | b;

	return argb1555;
}

uint32_t argb1555_to_argb8888(uint16_t color)
{
	uint32_t a = (color & 0x8000) >> 15;
	uint32_t r = (color & 0x7C00) >> 10;
	uint32_t g = (color & 0x03E0) >> 5;
	uint32_t b = (color & 0x001F);

	uint32_t argb8888 = (a << 24) | (r << 16) | (g << 8) | b;

	return argb8888;
}

int32_t rgb888_to_argb1555(uint8_t *rgb, uint32_t size, uint16_t *argb1555)
{
	if(rgb == NULL || argb1555 == NULL){
		return -1;
	}

    for(int i = 0; i < size / 3; i++){
        uint8_t r = rgb[i * 3 + 0];
        uint8_t g = rgb[i * 3 + 1];
        uint8_t b = rgb[i * 3 + 2];

        argb1555[i] = 0x8000 | (((b & 0xf8) >> 3) << 10) | (((g & 0xf8) >> 3) << 5) | ((r & 0xf8) >> 3);
    }

	return 0;
}

int32_t argb1555_to_rgb888(uint16_t *argb1555, uint32_t size, uint8_t *rgb)
{
	return 0;
}

int32_t check_mount_device(const char *pdev)
{
    int32_t ret = 0;
    FILE *fp;
    char line[1024];

    fp = fopen("/proc/mounts", "r");
    if(!fp) {
		return -1;
	}

    while(!feof(fp)) {
		char *tmp = fgets(line, 1024, fp);
        if(strstr(line, "/media") && strstr(line, pdev)){
            ret = 1;
            break;
        }
	}
    fclose(fp);
    return ret;
}

/*
* @brief:二分查找算法(double类型数组)，找到数组中与目标最近的元素索引
*/

int32_t binary_search_double(double *arr, int32_t low, int32_t high, double target)
{
    int32_t closest_index = -1;
    double min_diff = INFINITY;

    while (low <= high) {
        int32_t mid = low + (high - low) / 2;
        double diff = abs(arr[mid] - target);

        if (diff == 0) {
            return mid;      // 找到与目标值相等的元素，直接返回其索引
        }

        if (diff < min_diff) {
            min_diff = diff;
            closest_index = mid;
        }
        
        if (arr[mid] < target) {
            low = mid + 1;
        } else {
            low = mid - 1;
        }
    }

    return closest_index;    // 未找到目标值，返回最近的元素索引
}

void output_framrate(uint8_t *module, uint32_t interval, struct timeval *tm_start, uint32_t *fps_count)
{
    struct timeval end;
    int delta_time;

    (*fps_count)++;
    gettimeofday(&end, NULL);
    delta_time = (end.tv_sec - tm_start->tv_sec) * 1000 + (end.tv_usec - tm_start->tv_usec) / 1000;

    if(delta_time >= (interval * 1000)){
        uint32_t fps = 0;
        fps = (*fps_count) / interval;
        printf("%s fps:%d\n", module, fps);
        *fps_count = 0;
        gettimeofday(tm_start, NULL);
    }
}
